package au.com.mithril.whereami;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.telephony.SmsManager;
import android.text.TextUtils;
import android.text.method.ScrollingMovementMethod;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import au.com.mithril.whereami.LocationHandler.LocationUpdater;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesClient;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.android.gms.location.LocationClient;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;

public class WhereActivity extends Activity implements
		GooglePlayServicesClient.ConnectionCallbacks,
		GooglePlayServicesClient.OnConnectionFailedListener, LocationListener, LocationUpdater {

	LocationManager mLocationManager;
	LocationHandler mLocationHandler;
	LocationClient mLocationClient;
	LocationRequest mLocationRequest;
	boolean mUpdatesRequested = false;
	Location mLastLocation;
	boolean mAskHelp = false;
	String mMessage;
	SharedPreferences mPreferences;
	MessageBox mMessageBox;
	public static final int PICK_CONTACT = 1;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_where);
		mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
		mLocationHandler = new LocationHandler(this);
		mLocationHandler.setUpdater(this);
		mLocationRequest = LocationRequest.create();
		mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
		mLocationRequest.setInterval(10000); // 10 seconds
		if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
			mLocationClient = new LocationClient(this, this, this);
		}
		mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
		mMessageBox=new MessageBox(this,"WhereAmI");
		setIdText(R.id.ePhone, mPreferences.getString("MAINPHONE", ""));
		((TextView) findViewById(R.id.textView1)).setMovementMethod(new ScrollingMovementMethod());
		setGPS(true);
		setLocationUpdates(true);
		clickPlay(null);
	}

	@Override
	protected void onDestroy() {
		mLocationHandler.stopLocating();
		Editor e = mPreferences.edit();
		e.putString("MAINPHONE", getIdText(R.id.ePhone));
		e.commit();
		super.onDestroy();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.where, menu);
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		if (item.getItemId()==R.id.menuLocation) {
			clickLocation(null);
			return true;
		} else if (item.getItemId()==R.id.menuToggleGps) {
			setGPS(!mLocationHandler.isLocating());
			return true;
		} else if (item.getItemId()==R.id.menuMessage) {
			normalMessage("");
			return true;
		} else if (item.getItemId()==R.id.menuLocationSettings) {
			changeLocationSettings();
			return true;
		} else if (item.getItemId()==R.id.menuContacts) {
			addContact();
			 return true;
		} else if (item.getItemId()==R.id.menuAbout) {
			PackageInfo pInfo;
			String version = "Unknown";
			try {
				pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
				version=pInfo.versionName;
			} catch (NameNotFoundException e) {
			}
			mMessageBox.showMessage("Version "+version);
			return true;
		}
		
		return super.onMenuItemSelected(featureId, item);
	}
	
	@Override  
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
	    if (resultCode == RESULT_OK) {  
	        switch (requestCode) {  
	        case PICK_CONTACT:
	            Cursor cursor = null;  
	            String phoneNumber = "";
	            List<String> allNumbers = new ArrayList<String>();
	            int phoneIdx = 0;
	            try {  
	                Uri result = data.getData();  
	                String id = result.getLastPathSegment();  
	                cursor = getContentResolver().query(Phone.CONTENT_URI, null, Phone.CONTACT_ID + "=?", new String[] { id }, null);  
	                phoneIdx = cursor.getColumnIndex(Phone.DATA);
	                if (cursor.moveToFirst()) {
	                    while (cursor.isAfterLast() == false) {
	                        phoneNumber = cursor.getString(phoneIdx);
	                        allNumbers.add(phoneNumber);
	                        cursor.moveToNext();
	                    }
	                } else {
	                    //no results actions
	                }  
	            } catch (Exception e) {  
	               addln(e.getMessage());
	            } finally {  
	                if (cursor != null) {  
	                    cursor.close();
	                }

	                final CharSequence[] items = allNumbers.toArray(new String[allNumbers.size()]);
	                AlertDialog.Builder builder = new AlertDialog.Builder(this);
	                builder.setTitle("Choose a number");
	                builder.setItems(items, new DialogInterface.OnClickListener() {
	                    public void onClick(DialogInterface dialog, int item) {
	                        String selectedNumber = items[item].toString();
	                        selectedNumber = selectedNumber.replace("-", "");
	                        setIdText(R.id.ePhone,selectedNumber);
	                    }
	                });
	                AlertDialog alert = builder.create();
	                if(allNumbers.size() > 1) {
	                    alert.show();
	                } else {
	                    String selectedNumber = phoneNumber.toString();
	                    selectedNumber = selectedNumber.replace("-", "");
	                    setIdText(R.id.ePhone,selectedNumber);
	                }
	            }  
	            break;  
	        }  
	    } else {
	       //activity result error actions
	    }  
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);
		mAskHelp = savedInstanceState.getBoolean("KEY_ASKHELP");
		mMessage = savedInstanceState.getString("KEY_MESSAGE");
		if (mAskHelp)
			clickHelp(null);
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		outState.putBoolean("KEY_ASKHELP", mAskHelp);
		outState.putString("KEY_MESSAGE", mMessage);
		super.onSaveInstanceState(outState);
	}

	public void setIdText(int id, String text) {
		View v = findViewById(id);
		if (v != null) {
			if (v instanceof TextView)
				((TextView) v).setText(text);
		}
	}

	public String getIdText(int id) {
		View v = findViewById(id);
		if (v != null) {
			if (v instanceof TextView)
				return ((TextView) v).getText().toString();
		}
		return "";
	}

	public void showLog(String s) {
		setIdText(R.id.textView1, s);
	}
	
	public void showStatus(String s) {
		setIdText(R.id.lbStatus,s);
	}

	public void addln(String s) {
		TextView tv = (TextView) findViewById(R.id.textView1);
		if (tv.getText().length() > 0)
			s = "\n" + s;
		tv.append(s);
	}
	
	public void addlx(String s) {
		addln(s);
		showStatus(s);
	}

	public void setGPS(boolean onOff) {
		if (onOff) {
			mLocationHandler.startLocating(30, 20);
		} else {
			mLocationHandler.stopLocating();
		}
	}

	public void clickLocation(View view) {
		StringBuilder b = new StringBuilder();
		showLog("Checking Location");
		for (String name : mLocationHandler.getProviders()) {
			LocationProvider provider = mLocationManager.getProvider(name);
			b.append("\n"
					+ provider.getName()
					+ " "
					+ (mLocationManager.isProviderEnabled(name) ? "enabled"
							: "disabled"));
			b.append("\n  Power "
					+ LocationHandler.getPowerName(provider
							.getPowerRequirement()) + " Acc: "
					+ LocationHandler.getAccuracyName(provider.getAccuracy()));

			String status = mLocationHandler.readStatus().get(name);
			if (status != null)
				b.append("\n  Status: " + status);
			Location location = mLocationHandler.readLocation().get(name);
			if (location != null) {
				b.append("\n  Loc: " + locationString(location));
				checkUpdateLocation(location);
			}
		}
		if (getClient()!=null) {
			b.append("\nGooglePlay: "+locationString(mLocationClient.getLastLocation()));
		}
		b.append("\nCurrent: "+locationString(mLastLocation));
		showLog(b.toString());
	}
	
	public void clickFalse(View view) {
		if (mAskHelp) {
			mAskHelp=false;
			setLocationUpdates(false);
			showStatus("Help Cancelled");
		} else {
			normalMessage("False Alarm.");
		}
	}

	public void normalMessage(String msg) {
	  mMessageBox.askInputMessage("Where Am I", "Enter a message to send with your location.", msg, new DialogInterface.OnClickListener() {
	      
	      @Override
	      public void onClick(DialogInterface dialog, int which) {
	        mMessage=mMessageBox.getEditValue();
	        startMessage();
	      }
	    });	
	}
	
	public void clickMap(View view) {
		if (mLastLocation == null)
			showLog("No Location");
		else {
			String s = String.format(Locale.ENGLISH,
					"geo:0,0?q=%1.6f,%1.6f(Accuracy=%1.0fm)",
					mLastLocation.getLatitude(), mLastLocation.getLongitude(),
					mLastLocation.getAccuracy());
			Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(s));
			startActivity(intent);
		}
	}

	public void clickPlay(View view) {
		StringBuilder b = new StringBuilder("Checking GooglePlay");
		int ret = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
		if (ret == ConnectionResult.SUCCESS)
			showLog("GooglePlay installed");
		else {
			Dialog d = GooglePlayServicesUtil.getErrorDialog(ret, this, 101);
			d.show();
			return;
		}
		b.append("\nGooglePlay installed "
				+ GooglePlayServicesUtil.getErrorString(ret));

		if (mLocationClient.isConnected()) {
			b.append("\nLoc "
					+ locationString(mLocationClient.getLastLocation()));
		} else if (mLocationClient.isConnecting()) {
			b.append("\nConnecting...");
		} else {
			b.append("\nConnect Called");
			mLocationClient.connect();
		}
		showLog(b.toString());
	}

	public LocationClient getClient() {
		if (mLocationClient == null) {
			if (GooglePlayServicesUtil.isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS) {
				mLocationClient = new LocationClient(this, this, this);
			}
		}
		return mLocationClient;
	}

	public void clickHelp(View view) {
		showStatus("Help Clicked");
		showLog("Help Clicked");
		mMessage="Testing Help.\nGet Help!";
        startMessage();
	}
	
	public void clickLocationSettings(View view) {
		mMessageBox.promptMessage("Where Am I", "Some Location services are not enabled. Change settings?", new Dialog.OnClickListener() {
			
			@Override
			public void onClick(DialogInterface dialog, int which) {
				changeLocationSettings();
			}
		});
	}

	public void changeLocationSettings() {
		Intent intent = new Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
		startActivity(intent);
	}
	
	public void addContact() {
		 Intent intent = new Intent(Intent.ACTION_PICK);
		 intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
		 startActivityForResult(intent, PICK_CONTACT); 			
	}
	
	public void startMessage() {
		if (TextUtils.isEmpty(getIdText(R.id.ePhone))) {
			mMessageBox.promptMessage("Where Am I","You need to set a phone number",new DialogInterface.OnClickListener() {
				
				@Override
				public void onClick(DialogInterface dialog, int which) {
					addContact();
				}
			});
			return;
		}
		mAskHelp = true;
		addln("Activating GPS");
		setGPS(true);
		addln("Turn on wifi");
		enableWifi(true);
		addln("Turning on GooglePlay");
		setLocationUpdates(true);
		if (getClient() != null && mLocationClient.isConnected()) {
			checkUpdateLocation(mLocationClient.getLastLocation());
		}
		for (String provider : mLocationHandler.readLocation().keySet()) {
			Location loc=mLocationHandler.readLocation().get(provider);
			if (loc!=null) checkUpdateLocation(loc);
		}
		
		if (!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) ||
				!mLocationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
			clickLocationSettings(null);
		}
		if (mAskHelp && mLastLocation!=null) checkHelpLocation();
	}

	public void checkHelpLocation() {
		if (mLastLocation == null) return;
		if (!mLastLocation.hasAccuracy()) return;
		if (mLastLocation.getAccuracy() > 100 || System.currentTimeMillis()-mLastLocation.getTime()>120000) { // 100M or 2 minutes. Should we make settable?
			addlx("Waiting for a more accurate location");
		} else {
			addln("Sending location " + locationString(mLastLocation));
			String s = String.format(Locale.ENGLISH,
					"http://maps.google.com/maps?q=%1.6f,%1.6f(Within+%1.0fm)",
					mLastLocation.getLatitude(), mLastLocation.getLongitude(),
					mLastLocation.getAccuracy());
			addln("SMS sending to " + getIdText(R.id.ePhone));
			try {
				sendSMS(getIdText(R.id.ePhone),
						mMessage+" I'm at \n" + s);
				addlx("SMS Sent");
				mMessageBox.showMessage("SMS Sent.");
			} catch (Exception e) {
				addlx("Invalid SMS");
			}
			mAskHelp = false;
			setLocationUpdates(false);
		}
	}

	public void toast(String text) {
		Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
	}

	public void enableWifi(boolean onOff) {
		WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
		wifi.setWifiEnabled(onOff);
	}

	private void sendSMS(String phoneNumber, String message) {
		SmsManager sms = SmsManager.getDefault();
		sms.sendTextMessage(phoneNumber, null, message, null, null);
	}

	public void setLocation(Location newLoc) {
		if (newLoc==null) return;
		mLastLocation = newLoc;
		addln("New: " + locationString(newLoc));
		setIdText(R.id.lbAccuracy, String.format(Locale.ENGLISH,"Accuracy: %1.0fm",newLoc.getAccuracy()));
		if (mAskHelp)
			checkHelpLocation();
	}

	public void checkUpdateLocation(Location newLoc) {
		if (newLoc==null) return;
		if (mLastLocation == null)
			setLocation(newLoc);
		else {
			float distance = newLoc.distanceTo(mLastLocation);
			long timediff = newLoc.getTime() - mLastLocation.getTime();
			float lastAcc = mLastLocation.getAccuracy();
			float newAcc = newLoc.getAccuracy();
			if (timediff > -300000) // check at new is no more than 5mins older
									// than the last.
			{
				if (lastAcc > newAcc || distance > newAcc) {
					setLocation(newLoc);
				}
			}
		}
	}

	public void setLocationUpdates(boolean onOff) {
		mUpdatesRequested = onOff;
		if (getClient() == null)
			return;
		if (mUpdatesRequested) {
			if (!(mLocationClient.isConnected() || mLocationClient
					.isConnecting()))
				mLocationClient.connect();
			else
				mLocationClient.requestLocationUpdates(mLocationRequest, this);
		} else {
			if (mLocationClient.isConnected()) {
				mLocationClient.removeLocationUpdates(this);
			}
		}
	}

	@SuppressLint({ "DefaultLocale", "SimpleDateFormat" })
	public String locationString(Location location) {
		SimpleDateFormat fmt = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
		String result = String.format("%1.5f,%1.5f acc=%1.0fm",
				location.getLatitude(), location.getLongitude(),
				location.getAccuracy());
		Date date = new Date(location.getTime());
		result = result + "@" + fmt.format(date);
		return result;
	}

	@Override
	public void onConnectionFailed(ConnectionResult result) {
		addln("Connection failed " + result.toString());

	}

	@Override
	public void onConnected(Bundle arg0) {
		addln("Connected to GooglePlay");
		if (mUpdatesRequested) {
			mLocationClient.requestLocationUpdates(new LocationRequest(), this);
		}
	}

	@Override
	public void onDisconnected() {
		addln("Disconnected");
	}

	@Override
	public void onLocationChanged(Location loc) {
		addln("Loc " + locationString(loc));
		checkUpdateLocation(loc);
	}

	@Override
	public void locationUpdate(LocationHandler handler, Location location) {
		checkUpdateLocation(location);
	}
}
